package com.justgame.project.base.interceptor;

import com.justgame.project.base.annotation.ProtectAccess;
import com.justgame.project.cloud.common.exception.Exc;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;


/**
 * 访问频率保护拦截器
 */
@Component
@AllArgsConstructor
public class ProtectAccessInterceptor implements HandlerInterceptor {

    /**
     * 判断是否开启ProtectAccess
     *
     * @param protectAccess 实例对象
     * @return boolean
     */
    private boolean hasEnable(ProtectAccess protectAccess) {
        if (protectAccess == null) {
            return false;
        } else {
            return protectAccess.enable();
        }
    }

    /**
     * 获取当前实例对象
     *
     * @param handler handler
     * @return ProtectAccess
     */
    private ProtectAccess getInstantiation(Object handler) {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        return method.getAnnotation(ProtectAccess.class);
    }

    /**
     * 转换时间
     *
     * @param protectAccess
     * @return
     */
    private long parseToSeconds(ProtectAccess protectAccess) {
        long baseTime = protectAccess.value();
        switch (protectAccess.frequencyType()) {
            case SECOND:
                break;
            case MINUTE:
                baseTime *= 60;
                break;
            case HOUR:
                baseTime *= 60 * 60;
                break;
            case DAY:
                baseTime *= 60 * 60 * 24;
                break;
        }
        return baseTime;
    }

    public boolean doFrequencyProtect(HttpServletRequest request, ProtectAccess protectAccess) {
        HttpSession session = request.getSession();
        Long prevAccessTime = (Long) session.getAttribute(request.getRequestURI());
        if (prevAccessTime != null) {
            long currentAccessTime = System.currentTimeMillis();
            /* 时间戳与秒换算 */
            if (currentAccessTime - prevAccessTime <= parseToSeconds(protectAccess) * 1000) {
                return false;
            }
        }
        session.setAttribute(request.getRequestURI(), System.currentTimeMillis());
        return true;
    }

    /**
     * 简易处理多次访问接口
     *
     * @param request
     */
    private boolean doAccessFilter(HttpServletRequest request, ProtectAccess protectAccess) {
        return doFrequencyProtect(request, protectAccess);
    }

    @SneakyThrows
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if (handler instanceof HandlerMethod) {
            ProtectAccess protectAccess = getInstantiation(handler);
            if (hasEnable(protectAccess)) {
                if (!doAccessFilter(request, protectAccess)) {
                    throw new Exc(protectAccess.message());
                }
            }
        }
        return true;
    }
}
